import * as Koa from 'koa';
import { Transaction } from 'tiny-entity2';
import { Guid, route, RouteOptionsBase, ServiceManager, Tools, UsingLock } from "../../common";
import { ServiceException } from '../../common/excpetion';
import { ApiDataContext } from '../../domain/apiDataContext';
import { User } from '../../domain/models/user';
import { Account } from '../../domain/models/account';
import { UserService } from '../../service/UserService';
import { OrganizationTreeService } from '../../service/organizationTreeService';
import { OrganizationTree } from '../../domain/models/organizationTree';
import { AccountService } from '../../service/accountService';

const userSvr = ServiceManager.Current.GetService<UserService>('UserService');
const orzTreeSvr = ServiceManager.Current.GetService<OrganizationTreeService>('OrganizationTreeService');
const accSvr = ServiceManager.Current.GetService<AccountService>('AccountService');

class UserController {
    @route(new RouteOptionsBase('GET', '/api/user'))
    async queryUsers(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let params = ctx.query;
        params.organizationId = rootOrgId;

        let users = await userSvr.QueryUser(params);
        ctx.response.body = users;

        await next();
    }
    @route(new RouteOptionsBase('GET', '/api/user/:id'))
    async getUserInfoById(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let id = ctx.params.id;
        let user = await userSvr.GetUserById(id);

        let orgtrees: OrganizationTree[] = await orzTreeSvr.QueryOrganizationTree({ objectName: user.ClassName(), objectId: id, organizationId: rootOrgId });
        user.orgTree = <OrganizationTree>{};
        if (orgtrees && orgtrees.length > 0) {
            user.orgTree = orgtrees[0];
        }
        let acc: Account = await accSvr.GetAccountById(user.accountId);
        user.acc = acc;

        if (user.orgTree.parentId) {
            user.departmentNode = await orzTreeSvr.GetOrganizationTreeById(user.orgTree.parentId);
        }
        else {
            user.departmentNode = null;
        }


        ctx.response.body = user;
        await next();
    }
    @route(new RouteOptionsBase('POST', '/api/user'))
    async createUser(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let user: User = ctx.request.body;
        user.orgTree.organizationId = rootOrgId;
        user.organizationId = rootOrgId;

        checkData(user);

        user.id = Guid.GetGuid();
        user.isDelete = false;
        var today = Date.now();
        user.createTime = today;

        let userTreeNode = new OrganizationTree();
        userTreeNode.id = Guid.GetGuid();
        if (rootOrgId) {
            userTreeNode.organizationId = rootOrgId;
        }

        let acc: Account = new Account();
        acc.id = Guid.GetGuid();
        acc.username = user.acc.username;
        acc.password = user.acc.password;
        acc.isDelete = false;

        await Transaction(new ApiDataContext(), async datactx => {
            let result = new User();
            acc.verifyMode = result.ClassName();
            let accResult: Account = await accSvr.CreateAccount(acc);
            user.accountId = acc.id;

            // user.departmentId = user.orgTree.parentId;
            result = await userSvr.CreateUser(user, datactx);
            result.acc = accResult;

            userTreeNode.objectId = result.id;
            userTreeNode.objectName = result.ClassName();
            userTreeNode.nodeName = result.name;
            userTreeNode.parentId = user.orgTree.parentId;
            userTreeNode.id = Guid.GetGuid();
            userTreeNode.isDelete = false;
            result.orgTree = await orzTreeSvr.CreateorganizationTree(userTreeNode, datactx);

            ctx.response.body = result;
        });

        await next();
    }
    @route(new RouteOptionsBase('PUT', '/api/user'))
    async updateUser(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let user: User = ctx.request.body;
        user.orgTree.organizationId = rootOrgId;
        user.organizationId = rootOrgId;

        if (!user.id) {
            throw new ServiceException('id 不能为空！');
        }

        if (!user.accountId) {
            throw new ServiceException('账号Id 不能为空！');
        }
        if (!user.acc) {
            user.acc = new Account();
            user.acc.id = user.accountId;
        }

        let userData = await userSvr.GetUserById(user.id);
        const userAccount = await accSvr.GetAccountById(user.accountId);
        if (userAccount.superPermits && userAccount.superPermits.length > 0) {
            throw new ServiceException(`用户【${userData.name}】具有超级权限，无法修改！`);
        }

        checkData(user);

        let userTreeNode: OrganizationTree = user.orgTree;
        if (rootOrgId) {
            userTreeNode.organizationId = rootOrgId;
        }

        let acc: Account = user.acc;
        // acc.username = user.employeeNo;

        await UsingLock(acc.id, async () => {
            await Transaction(new ApiDataContext(), async datactx => {
                let result = new User();
                acc.verifyMode = result.ClassName();
                let accData = await accSvr.GetAccountById(acc.id);

                if (acc.password && acc.password.length > 0 && acc.password != accData.password) {
                    acc.password = acc.password;
                }

                accData.username = acc.username ? acc.username : accData.username;
                accData.verifyMode = acc.verifyMode ? acc.verifyMode : accData.verifyMode;
                accData.isDelete = acc.isDelete ? acc.isDelete : accData.isDelete;
                accData.password = acc.password ? acc.password : accData.password;

                let accResult: Account = await accSvr.UpdateAccount(accData);

               
                userData = Tools.ConvertToObject(user, userData);

                result = await userSvr.UpdateUser(userData, datactx);

                result.acc = accResult;

                userTreeNode.objectId = result.id;
                userTreeNode.objectName = result.ClassName();
                userTreeNode.nodeName = result.name;
                userTreeNode.parentId = user.orgTree.parentId;
                userTreeNode.id = user.orgTree.id;

                let orgTreeDatas = await orzTreeSvr.QueryOrganizationTree({ objectId: userTreeNode.objectId });
                if (orgTreeDatas && orgTreeDatas.length > 0) {
                    let orgTreeData = orgTreeDatas[0];
                    orgTreeData = Tools.ConvertToObject(userTreeNode, orgTreeData);

                    result.orgTree = await orzTreeSvr.UpdateorganizationTree(orgTreeData, datactx);
                }
                ctx.response.body = result;
            });
        })

        await next();
    }
    @route(new RouteOptionsBase('DELETE', '/api/user/:id'))
    async deleteUser(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let id = ctx.params.id;

        if (!id) {
            throw new ServiceException('id 不能为空！', 'not_be_null');
        }
        let user = await userSvr.GetUserById(id);
        const userAccount = await accSvr.GetAccountById(user.accountId);
        if (userAccount.superPermits && userAccount.superPermits.length > 0) {
            throw new ServiceException(`用户【${user.name}】具有超级权限，无法删除！`);
        }
        user.isDelete = true;

        ctx.response.body = await UsingLock(user.id, async () => {
            await Transaction(new ApiDataContext(), async datactx => {
                let userData = await userSvr.GetUserById(user.id);
                userData.ConverToEntity(user);

                let account: Account = await accSvr.GetAccountById(userData.accountId);
    
                await accSvr.DeleteAccount(account, datactx);

                await userSvr.DeleteUserLogic(user.id, datactx);
                await orzTreeSvr.DeleteOrganizationTreeByObjectId(user.id, datactx);

                return user;
            });
        })

        await next();
    }
}

const checkData = (data: User) => {
    if (!data.name) {
        throw new ServiceException('未填写用户名称！');
    }
    if (!data.employeeNo) {
        throw new ServiceException('未填写用户工号！');
    }
    if (!data.organizationId) {
        throw new ServiceException('未传入所属组织编号！');
    }

    if (!data.orgTree.organizationId) {
        throw new ServiceException('未传入根组织编号！');
    }

    if (!data.phone) {
        throw new ServiceException('未传入手机号！');
    }
}